#include "ZeroCurve.h"
#include "MyVertex.h"

using namespace CAD_CAM;

namespace Curves
{

	CZeroCurve::CZeroCurve(void): VerticesMax(1000)
	{
		mVertexVBO = QGLBuffer(QGLBuffer::VertexBuffer);
		mIndexVBO = QGLBuffer(QGLBuffer::IndexBuffer);
		curveVertices = 0;
		filledSegment = 0;
		isInited = false;

		bezierPoints.reserve(VerticesMax);
		bezierIndices.reserve(VerticesMax);
		build();
	}

	CZeroCurve::~CZeroCurve(void)
	{
		mVertexVBO.release();
		mIndexVBO.release();
		mVertexVBO.destroy();
		mIndexVBO.destroy();
	}

	void CZeroCurve::build()
	{
		//for(int i=0; i< 1000; ) // TODO do zmiany
		//{
		//	bezierIndices.push_back(i);
		//	bezierIndices.push_back(++i);
		//	bezierIndices.push_back(++i);
		//	bezierIndices.push_back(++i);
		//}
	}


	void CZeroCurve::initBuffers(QGLBuffer::UsagePattern usage)
	{
		mVertexVBO.create();
		mIndexVBO.create();

		mVertexVBO.bind();
		mIndexVBO.bind();

		mVertexVBO.setUsagePattern(usage);
		mIndexVBO.setUsagePattern(usage);

		mVertexVBO.allocate(bezierPoints.data(), sizeof(MyVertex)*bezierPoints.count());
		mIndexVBO.allocate(bezierIndices.data(), sizeof(GLuint)*bezierIndices.count());
	
		mVertexVBO.release();
		mIndexVBO.release();
		isInited = true;
	}

	void CZeroCurve::replaceBezierPoint(const MyVertex & v, int i)
	{
		mVertexVBO.bind();
		MyVertex* vertices = (MyVertex*)mVertexVBO.map(QGLBuffer::ReadWrite);
		vertices[i] = v;
		mVertexVBO.unmap();
		mVertexVBO.release();
	}

	void CZeroCurve::addBezierVertex( const QVector3D & v)
	{
		if(curveVertices == 0) // pierwszy punkt to przypadek szczegolny
		{
			bezierIndices.insert(bezierIndices.count(), 4, 0);
		}
		else if(filledSegment == 0)
		{
			++filledSegment;
			bezierPoints.insert(bezierPoints.count(), 3, v); // bedziemy rozszerzac krzywa o kolejne punkty
			mVertexVBO.bind();
			mVertexVBO.allocate(bezierPoints.data(), sizeof(MyVertex)*bezierPoints.count());
			mVertexVBO.release();
		}
		else
		{
			if(++filledSegment == 3)
				filledSegment = 0;
			replaceBezierPoint(v, curveVertices);
		}
		curveVertices++;
	}

	void CZeroCurve::removeBezierVertex( int indx)
	{
		bezierPoints.remove(indx);
		mVertexVBO.bind();
		mVertexVBO.allocate(bezierPoints.data(), sizeof(MyVertex)*bezierPoints.count());
		mVertexVBO.release();
		curveVertices--;
	}

	void CZeroCurve::DrawShader(QGLShaderProgram& shaderProgram, QMatrix4x4& viewMatrix, QMatrix4x4& projectionMatrix)
	{
		if(isInited == false)
			initBuffers();
		mVertexVBO.bind();
		mIndexVBO.bind();
	
		QMatrix4x4 modelMatrix;

		shaderProgram.bind();

		int inPositionLocation = shaderProgram.attributeLocation("inPosition");
		int inColorLocation = shaderProgram.attributeLocation("inColor");

		int inModelMatrixLocation = shaderProgram.uniformLocation("inModelMatrix");
		int inViewMatrixLocation = shaderProgram.uniformLocation("inViewMatrix");
		int inProjectionMatrixLocation = shaderProgram.uniformLocation("inProjectionMatrix");

		int inCurveVerticesLocation = shaderProgram.uniformLocation("inCurveVertices");

		shaderProgram.enableAttributeArray(inPositionLocation);
		shaderProgram.enableAttributeArray(inColorLocation);

		shaderProgram.setAttributeBuffer(inPositionLocation, GL_FLOAT, 0, 3, sizeof(MyVertex));
		shaderProgram.setAttributeBuffer(inColorLocation, GL_FLOAT, 12, 3, sizeof(MyVertex));
		shaderProgram.setUniformValue(inModelMatrixLocation, modelMatrix);
		shaderProgram.setUniformValue(inViewMatrixLocation, viewMatrix);
		shaderProgram.setUniformValue(inProjectionMatrixLocation, projectionMatrix);
		shaderProgram.setUniformValue( inCurveVerticesLocation,curveVertices);

		glDrawElements(GL_LINES_ADJACENCY_EXT, bezierPoints.count(), GL_UNSIGNED_INT, 0);

		shaderProgram.disableAttributeArray(inPositionLocation);
		shaderProgram.disableAttributeArray(inColorLocation);
	
		shaderProgram.release();
	
		mVertexVBO.release();
		mIndexVBO.release();
	}
}